/*
 * JSFUtil.java
 * 
 * Copyright (c) 2011 Administrator. 
 * 
 * This file is part of RMS.
 * 
 * RMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * RMS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with RMS.  If not, see <http ://www.gnu.org/licenses/>.
 */
package com.itrustsolution.rms.util;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

/**
 *
 * @author Administrator
 */
public class JSFUtil {
    private static final String NO_RESOURCE_FOUND = "Missing resource: ";

  /**
   * Method for taking a reference to a JSF binding expression and returning
   * the matching object (or creating it).
   * @param expression
   * @return Managed object
   */
  public static Object resolveExpression(String expression) {
    FacesContext ctx = FacesContext.getCurrentInstance(); 
    Application app = ctx.getApplication();
    ValueBinding bind = app.createValueBinding(expression);
    return bind.getValue(ctx);
  }

  /**
   * Convenience method for resolving a reference to a managed bean by name
   * rather than by expression.
   * @param beanName
   * @return Managed object
   */
  public static Object getManagedBeanValue(String beanName) {
    StringBuffer buff = new StringBuffer("#{");
    buff.append(beanName);
    buff.append("}");
    return resolveExpression(buff.toString());
  }

  /**
   * Method for setting a new object into a JSF managed bean.
   * Note: will fail silently if the supplied object does
   * not match the type of the managed bean
   * @param expression
   * @param newValue
   */
  public static void setExpressionValue(String expression, 
                                        Object newValue) {
    FacesContext ctx = FacesContext.getCurrentInstance();                                        
    Application app = ctx.getApplication();
    ValueBinding bind = app.createValueBinding(expression);

    //Check that the input newValue can be cast to the property type
    //expected by the managed bean. 
    //If the managed Bean expects a primitive we rely on Auto-Unboxing
    //I could do a more comprehensive check and conversion from the object 
    //to the equivilent primitive but life is too short
    Class bindClass = bind.getType(ctx);
    if (bindClass.isPrimitive() || bindClass.isInstance(newValue)) {
      bind.setValue(ctx, newValue);
    }
  }

  /**
   * Convenience method for setting the value of a managed bean by name
   * rather than by expression.
   * @param beanName
   * @param newValue
   */
  public static void setManagedBeanValue(String beanName, 
                                         Object newValue) {
    StringBuffer buff = new StringBuffer("#{");
    buff.append(beanName);
    buff.append("}");
    setExpressionValue(buff.toString(), newValue);
  }


  /**
   * Convenience method for setting Session variables.
   * @param key object key
   * @param object value to store
   */
  public static void storeOnSession(String key, Object object) {
    FacesContext ctx = FacesContext.getCurrentInstance();
    Map sessionState = ctx.getExternalContext().getSessionMap();
    sessionState.put(key, object);
  }

  /**
   * Convenience method for getting Session variables.
   * @param key object key
   */
  public static Object getFromSession(String key) {
    FacesContext ctx = FacesContext.getCurrentInstance();
    Map sessionState = ctx.getExternalContext().getSessionMap();
    return sessionState.get(key);
  }


  /**
   * Pulls a String resource from the property bundle that
   * is defined under the application &lt;message-bundle&gt; element in
   * the faces config. Respects Locale
   * @param key
   * @return Resource value or placeholder error String
   */
  public static String getStringFromBundle(String key) {
    ResourceBundle bundle = getBundle();
    return getStringSafely(bundle, key, null);
  }


  /**
   * Convenience method to construct a <code>FacesMesssage</code>
   * from a defined error key and severity
   * This assumes that the error keys follow the convention of
   * using <b>_detail</b> for the detailed part of the
   * message, otherwise the main message is returned for the
   * detail as well.
   * @param key for the error message in the resource bundle
   * @param severity
   * @return Faces Message object
   */
  public static FacesMessage getMessageFromBundle(String key, FacesMessage.Severity severity) {
    ResourceBundle bundle = getBundle();
    String summary = getStringSafely(bundle, key, null);
    String detail = getStringSafely(bundle, key + "_detail", summary);
    FacesMessage message = new FacesMessage(summary, detail);
    message.setSeverity(severity);
    return message;
  }
  
  public static void addFacesErrorMessage(String msg) {
    FacesContext ctx = FacesContext.getCurrentInstance();
    FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR,msg,"");
    ctx.addMessage(getRootViewComponentId(),fm);
  }  
  
  public static void addFacesErrorMessage(String attrName, 
                                          String msg) {
    // TODO: Need a way to associate attribute specific messages
    //       with the UIComponent's Id! For now, just using the view id.
    //TODO: make this use the internal getMessageFromBundle?
     FacesContext ctx = FacesContext.getCurrentInstance();
     FacesMessage fm =  new FacesMessage(FacesMessage.SEVERITY_ERROR,attrName,msg);
     ctx.addMessage(getRootViewComponentId(),fm);
  }
  
  public static void addFacesMessage(FacesMessage.Severity typeMessage, String message){
      FacesContext ctx = FacesContext.getCurrentInstance();
      FacesMessage fm =  new FacesMessage(message);
      fm.setSeverity(typeMessage);
      ctx.addMessage(null,fm);
  }
  
  // Informational getters
   public static String getRootViewId() {
     FacesContext ctx = FacesContext.getCurrentInstance();
     return ctx.getViewRoot().getViewId();
   }
   public static String getRootViewComponentId() {
     FacesContext ctx = FacesContext.getCurrentInstance();
     return ctx.getViewRoot().getId();
   }  
  

  /*
   * Internal method to pull out the correct local
   * message bundle
   */
  private static ResourceBundle getBundle() {
    FacesContext ctx = FacesContext.getCurrentInstance();
    UIViewRoot uiRoot = ctx.getViewRoot();
    Locale locale = uiRoot.getLocale();
    ClassLoader ldr = Thread.currentThread().getContextClassLoader();
    return ResourceBundle.getBundle(ctx.getApplication().getMessageBundle(), 
                                    locale, ldr);
  }

   /*
    * Internal method to proxy for resource keys that don't exist
    */

  private static String getStringSafely(ResourceBundle bundle, String key, 
                                        String defaultValue) {
    String resource = null;
    try {
      resource = bundle.getString(key);
    } catch (MissingResourceException mrex) {
      if (defaultValue != null) {
        resource = defaultValue;
      } else {
        resource = NO_RESOURCE_FOUND + key;
      }
    }
    return resource;
  }
  
  /**
     * Digunakan untuk memformat date menjadi format dd-MM-yyyy
     * sehingga tanggal yang didapatkan benar2 tanggal(tanpa waktu)
     * @param date
     * @return
     */
    public static Date formatDate(Date date){
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        String res = sdf.format(date);
        Date result=null;
        try {
            result = sdf.parse(res);
        } 
        catch (ParseException e) { e.printStackTrace(); }
        return result;
    }
    
    /** Method untuk menampilkan pesan dari file properties.
    * @param bundleParam   Parameter di file properties.
    * @param moreString   Tambahan kata yang ingin ditampilkan. Jika tidak ada ganti dengan "".
    * @param soprintPrefix   Jika ingin ditampilkan di console. Jika tidak ganti dengan "".
    * @author ArieF
    */
    public static  void showMessageFromBundle( String bundleParam, String moreString, String soprintPrefix ) {
        showMessage( JSFUtil.getStringFromBundle( bundleParam ) +"  "+ moreString, soprintPrefix );
    }
    
    /** Method untuk menampilkan pesan.
    * @param message   Pesan yang ingin ditampilkan.
    * @param soprintPrefix   Jika ingin ditampilkan di console. Jika tidak ganti dengan "".
    * @author ArieF
    */
    public static  void showMessage( String message, String soprintPrefix ) {
        FacesContext.getCurrentInstance().addMessage( null, new FacesMessage(FacesMessage.SEVERITY_INFO, message, null) );
        if ( soprintPrefix != "" ) System.out.println( soprintPrefix +"  "+ message );
    }
}
